/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.apiGenerator.dataType.entityInterface.resourceInfo;

import com.inspur.edp.bef.bizentity.GspBizEntityElement;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.caf.generator.baseInfo.ParameterInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.compileunit.CompileUnitGeneratorContext;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.cef.api.repository.GspDbDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.*;
import com.inspur.edp.cef.entity.entity.FieldType;
import com.inspur.edp.cef.gencommon.MediateType;
import com.inspur.edp.cef.generator.DotNetToJavaStringHelper;
import com.inspur.edp.cef.generator.apiGenerator.dataType.entityInterface.DataTypeInterfaceGeneratorContext;
import com.inspur.edp.cef.generator.apiGenerator.dataType.entityInterface.resourceInfo.initcolumnsstragety.AddPropertyInfoStragetyFactory;
import com.inspur.edp.cef.generator.apiGenerator.dataType.entityInterface.resourceInfo.initcolumnsstragety.BaseExtendAddPropertyInfoProcessor;
import com.inspur.edp.cef.generator.apiGenerator.dataType.entityInterface.resourceInfo.initcolumnsstragety.ExtendAddPropertyInfoProcessor;
import com.inspur.edp.cef.generator.overall.GenUtils;
import com.inspur.edp.cef.generator.overall.Utils;
import com.inspur.edp.cef.spi.entity.AssociationEnableState;
import com.inspur.edp.cef.spi.entity.AssociationInfo;
import com.inspur.edp.cef.spi.entity.DefaultValueType;
import com.inspur.edp.cef.spi.entity.PropertyDefaultValue;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.AssocationPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.BasePropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.ComplexUdtPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DataTypePropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DynamicSetPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.EnumPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.EnumPropertyRepoType;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.ObjectType;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.SimpleAssoUdtPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.SimpleEnumUdtPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.SimpleUdtPropertyInfo;
import com.inspur.edp.cef.spi.jsonser.base.StringUtils;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.das.commonmodel.entity.GspCommonModel;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnMapType;
import java.math.BigDecimal;
import java.util.ArrayList;
import lombok.var;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BooleanLiteral;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.InfixExpression.Operator;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.TypeLiteral;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;

public class InitColumnsGenerator extends ClassMethodGenerator {

    private IGspCommonDataType dataType;
    private DataTypeInterfaceGeneratorContext parentContext;
    private ArrayList<String> varNames = new ArrayList<>();

    protected InitColumnsGenerator(IGspCommonDataType dataType, DataTypeInterfaceGeneratorContext parentContext) {
        this.dataType = dataType;
        this.parentContext = parentContext;
    }

    @Override
    protected String getMethodName() {
        return "initColumns";
    }

    @Override
    protected TypeInfo getReturnType() {
        return null;
    }

    @Override
    protected ArrayList<Modifier.ModifierKeyword> getAccessModifiers() {
        ArrayList<Modifier.ModifierKeyword> list = new ArrayList<>();
        list.add(Modifier.ModifierKeyword.PROTECTED_KEYWORD);
        return list;
    }

    @Override
    protected ArrayList<ParameterInfo> getParameterCollection() {
        return new ArrayList<>();
    }

    @Override
    protected boolean getIsOverride() {
        return true;
    }

    @Override
    protected Block buildMethodBody() {
        Block block = ast.newBlock();

        for (var field : dataType.getContainElements()) {
            if(field.getObjectType() == GspElementObjectType.Association && (field.getChildAssociations() ==null || field.getChildAssociations().size() == 0)){
                continue;
            }
            buildFieldPropertyInfo(block, field);
        }

        return block;
    }

    private void buildFieldPropertyInfo(Block block, IGspCommonField field) {
      if(field.getIsUdt()) {
        if (field.getObjectType() == GspElementObjectType.Association)
          buildNewPropertyInfo(block, field);
        else {
          UnifiedDataTypeDef udtDef = (UnifiedDataTypeDef) parentContext.getApiGenContext()
              .getCefGenContext().
                  getMetadataJitContext().getMetadata(field.getUdtID()).getContent();
          if (udtDef instanceof ComplexDataTypeDef
              )
            buildNewPropertyInfo(block, field);
          else if(udtDef instanceof SimpleDataTypeDef)
            buildNewPropertyInfo(block,field);
          else
            buildOtherFieldPropertyInfo(block, field);
        }
      }
      else
      {
        switch (field.getObjectType())
        {
          case None:
            buildNewPropertyInfo(block,field);
            break;
          case Association:
            buildNewPropertyInfo(block,field);
            break;
//          case Enum:
//            buildNewPropertyInfo(block,field);
//            break;
            default:
              buildOtherFieldPropertyInfo(block, field);
        }
      }
    }

  private void buildNewPropertyInfo(Block block, IGspCommonField field) {
    addImport(FieldType.class.getTypeName());
    addImport(ObjectType.class.getTypeName());
    addImport(GspDbDataType.class.getTypeName());
    addImport(com.inspur.edp.cef.spi.entity.AssoCondition.class.getTypeName());
    addImport(ArrayList.class.getTypeName());
    AddPropertyInfoStragetyFactory.getAddPropertyInfoStragety(block,dataType,field,ast,parentContext,
        getExtendAddPropertyInfoProcessor()).buildAddPropertyInfoStatement();
  }

protected ExtendAddPropertyInfoProcessor getExtendAddPropertyInfoProcessor() {
  return new BaseExtendAddPropertyInfoProcessor();
}

  private void buildOtherFieldPropertyInfo(Block block, IGspCommonField field) {
    MethodInvocation invocation = ast.newMethodInvocation();
    invocation.setName(ast.newSimpleName("addPropertyInfo"));
    ClassInstanceCreation creation = buildPropertyInfoCreation(block, null, field, false);
    invocation.arguments().add(creation);
    block.statements().add(ast.newExpressionStatement(invocation));
  }

  private ClassInstanceCreation buildPropertyInfoCreation(Block block, String belongField, IGspCommonField field, boolean isRefEle) {
    ClassInstanceCreation creation = ast.newClassInstanceCreation();
    creation.setType(
        new TypeInfo(getDataTypePropertyInfoType()).getType(ast, parentContext.getApiGenContext()));
    //① propertyName
    var arg1 = ExpressionUtils.getStringLiteral(ast, field.getLabelID());
    //② displayValueKey
    StringLiteral stringLiteralArg2 = ExpressionUtils
        .getStringLiteral(ast, field.getI18nResourceInfoPrefix() + "." + "Name");
    InfixExpression infixExpressionArg2 = null;
    if (!StringUtils.isEmpty(dataType.getI18nResourceInfoPrefix())
        && dataType.getI18nResourceInfoPrefix().equals(field.getI18nResourceInfoPrefix())) {
      InfixExpression infixExpression = ast.newInfixExpression();
      MethodInvocation methodInvocation = ast.newMethodInvocation();
      methodInvocation.setName(ast.newSimpleName("getI18nPrefix"));
      infixExpression.setLeftOperand(methodInvocation);
      infixExpression
          .setRightOperand(ExpressionUtils.getStringLiteral(ast, field.getLabelID() + ".Name"));
      infixExpression.setOperator(Operator.PLUS);
      infixExpressionArg2 = infixExpression;
    }
    //③ required
    var arg3 = ast.newBooleanLiteral(field.getIsRequire());
    //④ enableRtrim
    var arg4 = ast.newBooleanLiteral(field.isEnableRtrim());
    //⑤ length
    var arg5 = ast.newNumberLiteral(String.valueOf(field.getLength()));
    //⑥ precision
    var arg6 = ast.newNumberLiteral(String.valueOf(field.getPrecision()));
    //⑦ fieldType
    addImport(FieldType.class.getTypeName());
    var arg7 = ast.newQualifiedName(
        ast.newName(FieldType.class.getSimpleName()), ast.newSimpleName(getElementType(field)));
    //⑧ objectType
    addImport(ObjectType.class.getTypeName());
    var arg8 = ast.newQualifiedName(ast.newName(ObjectType.class.getName()),
        ast.newSimpleName(convert2ObjectType(field)));

    //⑨ objectInfo
    String varName = getVarName(
        "objectType" + (belongField != null ? belongField + "_" : "") + field.getLabelID(), 0);
    Expression arg9 = ast.newSimpleName(varName);
    IGspCommonField actualField = field;
    if (isRefEle) {
      GspCommonModel refModel = parentContext.getApiGenContext().getCefGenContext()
          .getMetadataContent("", field.getParentAssociation().getRefModelID());
      actualField = refModel.findElementById(field.getRefElementId());
    }
    if (actualField.getIsUdt()) {
      buildUdtStatement(block, field, actualField, varName, isRefEle);
    } else if (actualField.getObjectType() == GspElementObjectType.Association) {
      buildAssociationStatements(block, field, field, varName, isRefEle);
    } else if (actualField.getObjectType() == GspElementObjectType.Enum) {
      buildEnumStatements(block, field, varName, isRefEle);
    } else if (actualField.getObjectType() == GspElementObjectType.DynamicProp) {
      buildDynPropSetStatements(block, field, varName, isRefEle);
    } else {
      arg9 = ast.newNullLiteral();
      // block.statements().add(buildNormalInfo(varName));
    }

    //⑩ defaultValue
    String defaultValueVarName = field.getLabelID() + "DefaultValue";
//        buildDefaultStatemets(block, field, defaultValueVarName);
    Expression arg10;

    if (dataType instanceof UnifiedDataTypeDef) {
      arg10 = ast.newNullLiteral();
    } else if (field.getObjectType() == GspElementObjectType.Enum && !field.getIsUdt()) {
      buildDefaultStatemets(block, field, defaultValueVarName);
      arg10 = ast.newSimpleName(defaultValueVarName);
    } else {
      arg10 = getMethodInvocationDefaultValue(field);
    }

    boolean isMultiLanguage = field.getIsMultiLanguage();
    ArrayList<Expression> args = new ArrayList<Expression>();

    args.add(arg1);
    args.add(infixExpressionArg2 == null ? stringLiteralArg2 : infixExpressionArg2);
    args.add(arg3);
    args.add(arg4);
    args.add(arg5);
    args.add(arg6);
    args.add(arg7);
    args.add(arg8);
    args.add(arg9);
    args.add(arg10);
    args.add(ast.newBooleanLiteral(isMultiLanguage));

    addExtendArgs(field, args);

    creation.arguments().addAll(args);
    if (actualField.getObjectType() == GspElementObjectType.Enum&&actualField instanceof GspBizEntityElement) {

      getExtendAddPropertyInfoProcessor()
          .addComplexExtendPropertyArgs(creation.arguments(), actualField, dataType, parentContext,
              ast);
    }

    return creation;
  }


    private String getVarName(String varName, int index){
        if(index == 0){
            if(!varNames.contains(varName)){
                varNames.add(varName);
                return varName;
            }else{
                return getVarName(varName, ++index);
            }
        }else{
            if(!varNames.contains(varName+index)){
                varName = varName+index;
                varNames.add(varName);
                return varName;
            }else{
                return getVarName(varName, ++index);
            }
        }
    }

    private String convert2ObjectType(IGspCommonField field) {
        if(field.getIsUdt())
            return ObjectType.UDT.toString();
        switch (field.getObjectType()) {
            case None:
                return ObjectType.Normal.toString();
            default:
                return field.getObjectType().toString();
        }
    }

//    private void buildDefaultStatemets(Block block, IGspCommonField field, String varName) {
  private Expression getMethodInvocationDefaultValue(IGspCommonField field) {
    return getDefaultValueExpression(field,ast,parentContext.getApiGenContext());
  }

  public static Expression getDefaultValueExpression(IGspCommonField field, AST ast,
      CompileUnitGeneratorContext compileUnitGeneratorContext) {
    if(field.getDefaultValue()==null||field.getDefaultValue().equals(""))
      return ast. newNullLiteral();
    MethodInvocation methodInvocation=ast.newMethodInvocation();

    compileUnitGeneratorContext.addImport(PropertyDefaultValue.class.getTypeName());
    methodInvocation.setExpression(ast.newSimpleName(PropertyDefaultValue.class.getSimpleName()));
    methodInvocation.setName(ast.newSimpleName("createDefaultValue"));
    methodInvocation.arguments().add(
        ExpressionUtils.getStringLiteral(ast,field.getDefaultValue()==null?"":field.getDefaultValue()));
    methodInvocation.arguments().add(ast.newQualifiedName(
        ast.newName(FieldType.class.getSimpleName()), ast.newSimpleName(getElementType(field))));
    if(field.getDefaultValueType()== ElementDefaultVauleType.Vaule)
      methodInvocation.arguments().add(ast.newQualifiedName(ast.newName(DefaultValueType.class.getSimpleName()),
          ast.newSimpleName("Value")));
    else
      methodInvocation.arguments().add(ast.newQualifiedName(ast.newName(DefaultValueType.class.getSimpleName()),
          ast.newSimpleName("Expression")));
    compileUnitGeneratorContext. addImport(DefaultValueType.class.getTypeName());

    return methodInvocation;
  }

  private void buildDefaultStatemets(Block block, IGspCommonField field, String varName) {
        if (field.getDefaultValueType() == ElementDefaultVauleType.Vaule) {
            block.statements().add(getRealValueStatement(field));
            block.statements().add(createDefaultInfo(field, varName));
        }
    }

    //region GetRealValue
    private Statement getRealValueStatement(IGspCommonField field) {
        Expression invocation = getRealValueInvocation(field);

        TypeInfo fieldType;
        if (field.getObjectType() == GspElementObjectType.Enum)
            fieldType = new TypeInfo(String.class);
        else
            fieldType = Utils.getNativeType(field, parentContext.getApiGenContext().getCefGenContext());

        var frag = ast.newVariableDeclarationFragment();
        frag.setName(ast.newSimpleName(field.getLabelID() + "RealValue"));
        frag.setInitializer(invocation);
        var statement = ast.newVariableDeclarationStatement(frag);
        statement.setType(fieldType.getType(ast, parentContext.getApiGenContext()));
        return statement;
    }

    private Expression getRealValueInvocation(IGspCommonField field) {
        Expression convertInvocation;
        if (field.getObjectType() == GspElementObjectType.Enum) {
            return getEnumValue(field);
        }
        if (field.getObjectType() != GspElementObjectType.None) {
            return getDefault(field);
        }
        switch (field.getMDataType()) {
            case Integer:
                convertInvocation = getConvertIntSyntax(field);
                break;
            case Decimal:
                convertInvocation = getConvertDecimalSyntax(field);
                break;
            case Boolean:
                convertInvocation = getConvertBoolSyntax(field);
                break;
            case Date:
            case DateTime:
                convertInvocation = getConvertDateSyntax();
                break;
            default:
                return getDefault(field);
        }

        return convertInvocation;
    }

    private Expression getEnumValue(IGspCommonField field) {
        var enums = field.getContainEnumValues();
        if (enums == null)
            throw new RuntimeException("字段" + field.getLabelID() + "上没有设置枚举项");
        String defaultValue = field.getDefaultValue();
        String realDefaultValue = null;
        boolean indexTypeString = field.getEnumIndexType() == EnumIndexType.String;
        for (var enumInfo : enums) {
            if (indexTypeString)
                realDefaultValue = getEnumDefaultValue(enumInfo.getStringIndex(), defaultValue, enumInfo);
            else
                realDefaultValue = getEnumDefaultValue(String.valueOf(enumInfo.getIndex()), defaultValue, enumInfo);

            if (realDefaultValue != null)
                break;
        }

        if (realDefaultValue == null)
            realDefaultValue = defaultValue;

        return ExpressionUtils.getStringLiteral(ast, realDefaultValue);
    }

    private String getEnumDefaultValue(String index, String defaultValue, GspEnumValue enumInfo) {
        if (index.equals(defaultValue))
            return enumInfo.getValue();
        return null;
    }

    private Expression getDefault(IGspCommonField field) {
        return ExpressionUtils.getStringLiteral(ast, field.getDefaultValue());

    }

    private MethodInvocation getConvertIntSyntax(IGspCommonField field) {
        var invocation = ExpressionUtils.getMethodInvocation(ast, "Integer", "parseInt");
        addImport("java.lang.Integer");
        invocation.arguments().add(ExpressionUtils.getStringLiteral(ast, field.getDefaultValue()));
        return invocation;
    }

    private MethodInvocation getConvertBoolSyntax(IGspCommonField field) {
        var invocation = ExpressionUtils.getMethodInvocation(ast, "Boolean", "parseBoolean");
        invocation.arguments().add(ExpressionUtils.getStringLiteral(ast, field.getDefaultValue()));
        return invocation;
    }

    private Expression getConvertDecimalSyntax(IGspCommonField field) {
        var invocation = GenUtils.buildClassInstantiation(ast, BigDecimal.class);
        invocation.arguments().add(ExpressionUtils.getStringLiteral(ast, field.getDefaultValue()));
        return invocation;
    }

    private Expression getConvertDateSyntax() {
        return ast.newNullLiteral();
    }

    //endregion

    //region CreateDefaultValue

    private Statement createDefaultInfo(IGspCommonField field, String varName) {

        TypeInfo typeInfo = new TypeInfo(PropertyDefaultValue.class);
        Expression expression = getDefaultValueInitExpression(field, typeInfo);
        VariableDeclarationFragment variableDeclarationFragment = ast.newVariableDeclarationFragment();
        variableDeclarationFragment.setName(ast.newSimpleName(varName));
        variableDeclarationFragment.setInitializer(expression);
        VariableDeclarationStatement variableDeclarationStatement = ast.newVariableDeclarationStatement(variableDeclarationFragment);
        variableDeclarationStatement.setType(typeInfo.getType(ast, parentContext.getApiGenContext()));

        return variableDeclarationStatement;
    }

    private Expression getDefaultValueInitExpression(IGspCommonField field, TypeInfo typeInfo) {
        if (!DotNetToJavaStringHelper.isNullOrEmpty(field.getDefaultValue())) {
            ClassInstanceCreation creationExpr = ast.newClassInstanceCreation();
            creationExpr.setType(typeInfo.getType(ast, parentContext.getApiGenContext()));

            StringLiteral valueArg = ast.newStringLiteral();
            valueArg.setLiteralValue(field.getDefaultValue());
            creationExpr.arguments().add(valueArg);

            var realValueArg = ast.newSimpleName(field.getLabelID() + "RealValue");
            creationExpr.arguments().add(realValueArg);

            QualifiedName valueTypeArg = ast.newQualifiedName(ast.newName(DefaultValueType.class.getName()), ast.newSimpleName("Value"));
            creationExpr.arguments().add(valueTypeArg);
            return creationExpr;
        } else {
            return ast.newNullLiteral();
        }
    }

    //endregion

    //region BuildDynPropSet
    private void buildDynPropSetStatements(Block block, IGspCommonField field, String varName,
        boolean isRefEle) {
      TypeInfo typeInfo = new TypeInfo(BasePropertyInfo.class);
      VariableDeclarationFragment variableDeclarationFragment = ast
          .newVariableDeclarationFragment();
      variableDeclarationFragment.setName(ast.newSimpleName(varName));

      ClassInstanceCreation dynPropInfoCreation = ast.newClassInstanceCreation();
      dynPropInfoCreation.setType(new TypeInfo(DynamicSetPropertyInfo.class)
          .getType(ast, parentContext.getApiGenContext()));
      dynPropInfoCreation.arguments().add(ExpressionUtils.getStringLiteral(ast,
          field.getDynamicPropSetInfo().getDynamicPropSerializerComp().getId()));
      variableDeclarationFragment.setInitializer(dynPropInfoCreation);
      VariableDeclarationStatement variableDeclarationStatement = ast
          .newVariableDeclarationStatement(variableDeclarationFragment);
      variableDeclarationStatement.setType(typeInfo.getType(ast, parentContext.getApiGenContext()));
      block.statements().add(variableDeclarationStatement);
    }
    //endregion

  //region BuildEnum
    private void buildEnumStatements(Block block, IGspCommonField field, String varName, boolean isRefEle) {
        block.statements().add(createEnumPropInfoStatement(varName,field));
        for (var enumItem : field.getContainEnumValues()) {
            block.statements().add(addEnumItemStatement(varName, enumItem));
        }

        String enumType = "";
        if (!isRefEle) {
            enumType = parentContext.getApiGenContext().getCefGenContext().getEntityGenContext().getElementEnumTypes().get(field.getID()).getFullName();

        }else if(field.getParentAssociation() != null){
          //关联带出字段是枚举
          IGspCommonField current = field;
          while(current.getParentAssociation() != null){
            GspCommonModel refModel = parentContext.getApiGenContext().getCefGenContext().getMetadataContent("", current.getParentAssociation().getRefModelID());
            current = refModel.findElementById(current.getRefElementId());
          }
          IGspCommonElement sourceElement = (IGspCommonElement) current;
            enumType = new MediateType(
                    sourceElement.getBelongObject().getGeneratedEntityClassInfo().getClassNamespace(),
                    sourceElement.getEnumTypeName()).getFullName();
        }else{
            //多值udt枚举字段
            //TODO 目前应该用不到
        }

        if("".equals(enumType))
            return;

        MethodInvocation invocation = ExpressionUtils.getMethodInvocation(ast, varName, "setEnumType");
        TypeLiteral typeLiteral = ast.newTypeLiteral();
        typeLiteral.setType(new TypeInfo(enumType).getType(ast, parentContext.getApiGenContext()));
        invocation.arguments().add(typeLiteral);
        block.statements().add(ast.newExpressionStatement(invocation));
    }

    private Statement createEnumPropInfoStatement(String varName,
        IGspCommonField field) {
        TypeInfo enumType = new TypeInfo(EnumPropertyInfo.class);

        ClassInstanceCreation creationExpr = ast.newClassInstanceCreation();
        creationExpr.setType(enumType.getType(ast, parentContext.getApiGenContext()));
        setEnumConsArg(creationExpr,field);
        VariableDeclarationFragment variableDeclarationFragment = ast.newVariableDeclarationFragment();
        variableDeclarationFragment.setName(ast.newSimpleName(varName));
        variableDeclarationFragment.setInitializer(creationExpr);
        VariableDeclarationStatement variableDeclarationStatement = ast.newVariableDeclarationStatement(variableDeclarationFragment);
        variableDeclarationStatement.setType(enumType.getType(ast, parentContext.getApiGenContext()));

        return variableDeclarationStatement;
    }

  private void setEnumConsArg(ClassInstanceCreation creationExpr, IGspCommonField field) {
    addImport(EnumPropertyRepoType.class.getTypeName());
    creationExpr.arguments().add(ast.newQualifiedName(
            ast.newName(EnumPropertyRepoType.class.getSimpleName()), ast.newSimpleName(getEnumRepoType(field))));
  }

  private String getEnumRepoType(IGspCommonField field) {
    if(field.getEnumIndexType()==EnumIndexType.Integer)
    return EnumPropertyRepoType.Index.toString();
    if(field.getContainEnumValues().get(0).getStringIndex()!=null&&field.getContainEnumValues().get(0).getStringIndex().equals("")==false)
      return EnumPropertyRepoType.StringIndex.toString();
    return EnumPropertyRepoType.Code.toString();
  }

  private Statement addEnumItemStatement(String varName, GspEnumValue enumValue) {
        MethodInvocation invocation = ExpressionUtils.getMethodInvocation(ast, varName, "addEnumValueInfo");
        invocation.arguments().add(ExpressionUtils.getStringLiteral(ast, enumValue.getI18nResourceInfoPrefix() + ".DisplayValue"));
        invocation.arguments().add(ExpressionUtils.getStringLiteral(ast, enumValue.getValue()));
        invocation.arguments().add(ExpressionUtils.getStringLiteral(ast, enumValue.getName()));
        invocation.arguments().add(ExpressionUtils.getStringLiteral(ast, enumValue.getStringIndex() == null ? "" : enumValue.getStringIndex()));
        invocation.arguments().add(ast.newNumberLiteral(String.valueOf(enumValue.getIndex())));

        return ast.newExpressionStatement(invocation);
    }
    //endregion

    //region BuildNormalInfo
    private Statement buildNormalInfo(String varName) {
        TypeInfo typeInfo = new TypeInfo(BasePropertyInfo.class);
        VariableDeclarationFragment variableDeclarationFragment = ast.newVariableDeclarationFragment();
        variableDeclarationFragment.setName(ast.newSimpleName(varName));
        variableDeclarationFragment.setInitializer(ast.newNullLiteral());
        VariableDeclarationStatement variableDeclarationStatement = ast.newVariableDeclarationStatement(variableDeclarationFragment);
        variableDeclarationStatement.setType(typeInfo.getType(ast, parentContext.getApiGenContext()));
        return variableDeclarationStatement;
    }
    //endregion

    //region BuildAssociation
    private void buildAssociationStatements(Block block, IGspCommonField belongField, IGspCommonField field, String propVarName, boolean isRefEle) {
      IGspCommonElement refedElement = null;
      if(isRefEle){
        GspCommonModel refModel = parentContext.getApiGenContext().getCefGenContext().getMetadataContent("", belongField.getParentAssociation().getRefModelID());
        refedElement = refModel.findElementById(belongField.getRefElementId());
      }
        GspAssociation association = (isRefEle ? refedElement : field).getChildAssociations().get(0);
        String varName = belongField.getLabelID() + "AssoInfo";
        String[] info = parseRef(association,parentContext);
      String sourceElement = association.getKeyCollection().get(0).getSourceElement();
      String targetElement = association.getKeyCollection().get(0).getTargetElement();
      AssociationInfo ass = getAssociationInfo(this.parentContext, association, this.dataType);

        block.statements().add(buildCreateAssoStatement(ast,parentContext,varName,info,association,ass.getPrivateSourceColumn(),ass.getPrivateTargetColumn(),AssociationInfo.class,""));
        for (var refEle : association.getRefElementCollection()) {
          MethodInvocation invocation = ExpressionUtils.getMethodInvocation(ast, varName,
              field instanceof IGspCommonElement && field.getIsUdt() && !refEle.getIsFromAssoUdt()
                  ? "addEnrichedRefProp" : "addRefProp");
            ClassInstanceCreation creation = buildPropertyInfoCreation(block, field.getLabelID(), refEle, true);
            invocation.arguments().add(ExpressionUtils.getStringLiteral(ast, refEle.getLabelID()));
            invocation.arguments().add(creation);
            block.statements().add(ast.newExpressionStatement(invocation));
        }

      String assoType = "";
      if(!field.getIsUdt()) {
        if (!isRefEle) {
          assoType = parentContext.getApiGenContext().getCefGenContext().getEntityGenContext()
              .getElementAssociationTypes().get(field.getID()).getFullName();

        } else if (field.getParentAssociation() != null) {
          //关联带出字段是关联
          GspCommonModel refModel = parentContext.getApiGenContext().getCefGenContext()
              .getMetadataContent("", field.getParentAssociation().getRefModelID());
          IGspCommonElement refElement = refModel.findElementById(field.getRefElementId());
          assoType = new MediateType(
              refedElement.getBelongObject().getGeneratedEntityClassInfo().getClassNamespace(),
              refedElement.getAssociationTypeName()).getFullName();
        } else {
          //多值udt关联字段
          //TODO 目前应该用不到
        }
      }

        Statement createStatement = buildCreateAssoPropStatement(propVarName, varName,assoType);
        block.statements().add(createStatement);
    }

    public static AssociationInfo getAssociationInfo(DataTypeInterfaceGeneratorContext dataTypeInterfaceGeneratorContext, GspAssociation gspAssociation, IGspCommonDataType gspCommonDataType){
        AssociationInfo associationInfo = new AssociationInfo();
        String sourceElementId = "";
        String targetElementId = "";
        for(GspAssociationKey key: gspAssociation.getKeyCollection()){
            sourceElementId = key.getSourceElement();
            targetElementId = key.getTargetElement();
        }
        associationInfo.setPrivateTargetColumn(gspAssociation.getBelongElement().getLabelID());
        GspMetadata metadata = dataTypeInterfaceGeneratorContext.getApiGenContext().getCefGenContext().
                getMetadataJitContext().getMetadata(gspAssociation.getRefModelID());
        GspBusinessEntity gspBusinessEntity = (GspBusinessEntity) metadata.getContent();
        IGspCommonObject refObject = null;
        if(gspAssociation.getRefObjectID() == null || "".equals(gspAssociation.getRefObjectID())){
            refObject = gspBusinessEntity.getMainObject();
        }else{
            refObject = gspBusinessEntity.findObjectById(gspAssociation.getRefObjectID());
        }

        if(refObject == null)
            throw new RuntimeException("被关联BE："+gspBusinessEntity.getCode()+"中，没有找到ID为"+gspAssociation.getRefObjectID()+"的节点，关联字段为"+gspCommonDataType.getCode()+"---"+gspAssociation.getBelongElement().getLabelID());
        IGspCommonField refField = refObject.findElement(sourceElementId);
        if(refField == null){
          throw new RuntimeException("被关联BE："+gspBusinessEntity.getCode()+"中，节点"+refObject.getCode()+"上不存在ID为"+ sourceElementId+"的字段, 关联字段为"+gspCommonDataType.getCode()+"---"+gspAssociation.getBelongElement().getLabelID());
        }
        associationInfo.setPrivateSourceColumn(refField.getLabelID());
        return associationInfo;
    }

    private Statement buildCreateAssoPropStatement(String propVarName, String varName,String assoType) {
        TypeInfo info = new TypeInfo(AssocationPropertyInfo.class);
        VariableDeclarationFragment fragment = ast.newVariableDeclarationFragment();
        fragment.setName(ast.newSimpleName(propVarName));
        ClassInstanceCreation creation = ast.newClassInstanceCreation();
        creation.setType(info.getType(ast, parentContext.getApiGenContext()));
        creation.arguments().add(ast.newSimpleName(varName));

        if(assoType!=null&&assoType.equals("")==false) {
          TypeLiteral typeLiteral = ast.newTypeLiteral();
          typeLiteral
              .setType(new TypeInfo(assoType).getType(ast, parentContext.getApiGenContext()));
          creation.arguments().add(typeLiteral);
        }
        fragment.setInitializer(creation);
        VariableDeclarationStatement statement = ast.newVariableDeclarationStatement(fragment);

        statement.setType(
                info.getType(ast, parentContext.getApiGenContext()));

        return statement;
    }

    public static Statement buildCreateAssoStatement(AST ast,DataTypeInterfaceGeneratorContext parentContext,String varName,String[] info,GspAssociation association,
        String sourceColumn,String targetColumn,Class associationClass,String assoInfoClass) {
      VariableDeclarationFragment fragment = ast.newVariableDeclarationFragment();
      fragment.setName(ast.newSimpleName(varName));
      ClassInstanceCreation creation = ast.newClassInstanceCreation();
      creation.setType(ast.newSimpleType(ast.newName(associationClass.getName())));

      StringLiteral valueLiteral = ast.newStringLiteral();
      valueLiteral.setLiteralValue(info[0]);
      creation.arguments().add(valueLiteral);

      StringLiteral nodeCodeLiteral = ast.newStringLiteral();
      nodeCodeLiteral.setLiteralValue(info[1]);
      creation.arguments().add(nodeCodeLiteral);

      StringLiteral mainCodeLiteral = ast.newStringLiteral();
      mainCodeLiteral.setLiteralValue(info[2]);
      creation.arguments().add(mainCodeLiteral);

      AssociationEnableState state =
          association.getForeignKeyConstraintType() == ForeignKeyConstraintType.Forbid
              ? AssociationEnableState.Disabled
              : AssociationEnableState.Enabled;
      parentContext.getApiGenContext().addImport(AssociationEnableState.class.getTypeName());
      QualifiedName enableStateValue =
          ast.newQualifiedName(
              ast.newName("AssociationEnableState"),
              ast.newSimpleName(state.toString()));
      creation.arguments().add(enableStateValue);

      StringLiteral sourceColumnLiteral = ast.newStringLiteral();
      sourceColumnLiteral.setLiteralValue(sourceColumn);
      creation.arguments().add(sourceColumnLiteral);

      StringLiteral targetColumnLiteral = ast.newStringLiteral();
      targetColumnLiteral.setLiteralValue(targetColumn);
      creation.arguments().add(targetColumnLiteral);

      if(assoInfoClass!=null&&"".equals(assoInfoClass)==false)
      {
        TypeLiteral typeLiteral = ast.newTypeLiteral();
        typeLiteral
            .setType(new TypeInfo(assoInfoClass).getType(ast, parentContext.getApiGenContext()));
        creation.arguments().add(typeLiteral);
      }

      fragment.setInitializer(creation);
      VariableDeclarationStatement statement = ast.newVariableDeclarationStatement(fragment);

      statement.setType(
          ast.newSimpleType(ast.newName(associationClass.getName())));

      return statement;
    }

    private Statement buildSetStringStatement(String varName, String value, String methodName) {
        MethodInvocation invocation = ExpressionUtils.getMethodInvocation(ast, varName, methodName);
        StringLiteral valueLiteral = ast.newStringLiteral();
        valueLiteral.setLiteralValue(value);
        invocation.arguments().add(valueLiteral);
        ExpressionStatement statement = ast.newExpressionStatement(invocation);
        return statement;
    }

    public static String[] parseRef(GspAssociation assocaition,DataTypeInterfaceGeneratorContext parentContext) {
        GspMetadata refMd = null; // 获取关联BE的元数据
        try {
            refMd = parentContext.getApiGenContext().getCefGenContext().getMetadata(assocaition.getRefModelPkgName(), assocaition.getRefModelID());
        } catch (Exception e) {
            throw new RuntimeException("关联元数据" + assocaition.getRefModelCode() + "获取失败", e);
        }
        GspBusinessEntity beEntity =
                (GspBusinessEntity)
                        ((refMd.getContent() instanceof GspBusinessEntity)
                                ? refMd.getContent()
                                : null); // 关联的BE
        if (beEntity == null) {
            throw new RuntimeException("关联元数据" + assocaition.getRefModelCode() + "获取失败,当前获取到的类型是" + refMd.getContent().getClass().getName());
        }

        String befConfig = beEntity.getGeneratedConfigID(); // 关联的BE的BefConfig
        String nodeCode = assocaition.getRefObjectCode(); // 关联的BE的节点编号
        if (DotNetToJavaStringHelper.isNullOrEmpty(nodeCode)) {
            nodeCode = beEntity.getMainObject().getCode();
        }
        String mainCode = beEntity.getMainObject().getCode();
        return new String[]{befConfig, nodeCode, mainCode};
    }
    //endregion

    //region BuildUDT
    private void buildUdtStatement(Block block, IGspCommonField belongField, IGspCommonField field, String varName, boolean isRefEle) {

        UnifiedDataTypeDef udtDef = (UnifiedDataTypeDef) parentContext.getApiGenContext().getCefGenContext().getMetadataJitContext().getMetadata(field.getUdtID()).getContent();

        if (udtDef instanceof ComplexDataTypeDef) {
            buildComplexUdtStatement(block, (ComplexDataTypeDef) udtDef, field, varName);
        } else if (field.getObjectType() == GspElementObjectType.Enum) {
            buildSimpleEnumUdtStatement(block, (SimpleDataTypeDef) udtDef, field, varName);
        } else if (field.getObjectType() == GspElementObjectType.Association) {
            if(field.getChildAssociations() != null && field.getChildAssociations().size() > 0){
              buildSimpleAssoUdtStatement(block, (SimpleDataTypeDef) udtDef, belongField, field, varName, isRefEle);
            }

        } else {
            buildSimpleUdtStatement(block, (SimpleDataTypeDef) udtDef, field, varName);
        }
    }

  private void buildSimpleUdtStatement(Block block, SimpleDataTypeDef udt, IGspCommonField field, String varName) {
    block.statements().add(createUdtInfoStatement(udt, varName, SimpleUdtPropertyInfo.class));
  }

  private void buildSimpleEnumUdtStatement(Block block, SimpleDataTypeDef udt, IGspCommonField field, String varName) {
        block.statements().add(createUdtInfoStatement(udt, varName, SimpleEnumUdtPropertyInfo.class));
        String enumPropName = getVarName(field.getLabelID() + "EnumInfo", 0);
        buildEnumStatements(block, field, enumPropName, true);

        MethodInvocation invocation = ExpressionUtils.getMethodInvocation(ast, varName, "setEnumInfo");
        invocation.arguments().add(ast.newSimpleName(enumPropName));
        block.statements().add(ast.newExpressionStatement(invocation));

    }

    private void buildSimpleAssoUdtStatement(Block block, SimpleDataTypeDef udt, IGspCommonField belongField, IGspCommonField field, String varName, boolean isRefEle) {
        block.statements().add(createUdtInfoStatement(udt, varName, SimpleAssoUdtPropertyInfo.class));
        String assoPropName = belongField.getLabelID() + "AssoPropInfo";

        buildAssociationStatements(block, belongField, field, assoPropName, isRefEle);

        MethodInvocation invocation = ExpressionUtils.getMethodInvocation(ast, varName, "setAssoInfo");
        invocation.arguments().add(ast.newSimpleName(assoPropName));
        block.statements().add(ast.newExpressionStatement(invocation));

        if(field.containRefElementNotFromAssoUdt()){
          String assoType = parentContext.getApiGenContext().getCefGenContext().getEntityGenContext().getElementAssociationTypes().get(field.getID()).getFullName();
          MethodInvocation setAssoTypeinvocation = ExpressionUtils.getMethodInvocation(ast, assoPropName, "setAssoType");
          TypeLiteral typeLiteral = ast.newTypeLiteral();
          typeLiteral.setType(ast.newSimpleType(ast.newName(assoType)));
          setAssoTypeinvocation.arguments().add(typeLiteral);
          block.statements().add(ast.newExpressionStatement(setAssoTypeinvocation));
        }
    }

    private void buildComplexUdtStatement(Block block, ComplexDataTypeDef udt, IGspCommonField field, String varName) {
        block.statements().add(createUdtInfoStatement(udt, varName, ComplexUdtPropertyInfo.class));
        if(generateChildElemnts()) {
            for (var childElement : field.getChildElements()) {
                var creation = buildPropertyInfoCreation(block, field.getLabelID(), childElement, false);
                MethodInvocation invocation = ExpressionUtils.getMethodInvocation(ast, varName, "addPropertyInfo");
                invocation.arguments().add(creation);
                block.statements().add(ast.newExpressionStatement(invocation));

//                StringLiteral stringLiteral=ast.newStringLiteral();
//                stringLiteral.setLiteralValue(childElement.getLabelID());
//                invocation.arguments().add(stringLiteral);
//
//                stringLiteral=ast.newStringLiteral();
//                stringLiteral.setLiteralValue(childElement.getI18nResourceInfoPrefix()+".Name");
//                invocation.arguments().add(stringLiteral);
//
//              IGspCommonField refField =   udt.findElement(field.getMappingRelation().getMappingInfo(childElement.getID()));
//              stringLiteral=ast.newStringLiteral();
//              stringLiteral.setLiteralValue(refField.getLabelID());
//              invocation.arguments().add(stringLiteral);
            }
        }
    }

    public Statement createUdtInfoStatement(UnifiedDataTypeDef udtDef, String varName, Class type) {
        TypeInfo info = new TypeInfo(type);
        StringLiteral stringLiteral = ast.newStringLiteral();
        stringLiteral.setLiteralValue(udtDef.getUdtType());
        BooleanLiteral booleanLiteral = ast.newBooleanLiteral(parentContext.getApiGenContext().getCefGenContext().getEnableStdDateTime());

        VariableDeclarationFragment fragment = ast.newVariableDeclarationFragment();
        fragment.setName(ast.newSimpleName(varName));
        ClassInstanceCreation creation = ast.newClassInstanceCreation();
        creation.setType(info.getType(ast, parentContext.getApiGenContext()));
        creation.arguments().add(stringLiteral);
        creation.arguments().add(booleanLiteral);
        fragment.setInitializer(creation);
        VariableDeclarationStatement statement = ast.newVariableDeclarationStatement(fragment);

        statement.setType(
                info.getType(ast, parentContext.getApiGenContext()));
        return statement;
    }

    //endregion

    protected Class getDataTypePropertyInfoType() {
        return DataTypePropertyInfo.class;
    }

    protected void addExtendArgs(IGspCommonField field, ArrayList<Expression> args) {

    }

    protected boolean generateChildElemnts(){
        return true;
    }

    private static String getElementType(IGspCommonField field) {
        // field --> FieldType
        if (field.getIsUdt()) {
            return FieldType.Udt.toString();
        }
        switch (field.getMDataType()) {
            case String:
                return FieldType.String.toString();
            case Binary:
                return FieldType.Binary.toString();
            case Boolean:
                return FieldType.Boolean.toString();
            case Date:
                return FieldType.Date.toString();
            case DateTime:
                return FieldType.DateTime.toString();
            case Decimal:
                return FieldType.Decimal.toString();
            case Integer:
                return FieldType.Integer.toString();
            case Text:
                return FieldType.Text.toString();
            default:
                throw new RuntimeException("当前没有类型为" + field.getMDataType() + "的字段");
        }
    }

}
